package repository

import (
	"context"
	"ehsm_kms/internal/ehsm"
	"ehsm_kms/internal/model"
	"encoding/base64"
	"errors"
	"go.uber.org/zap"
)

type UserInfoRepository interface {
	Store(ctx context.Context, appid string, apikey []byte, cmk, smDefaultCmk string) error
	GenHmac(ctx context.Context, appid string, data []byte) (string, error)
}

func NewUserInfoRepository(r *Repository, log *zap.Logger) UserInfoRepository {
	return &userInfoRepository{
		Repository: r,
		log:        log,
	}
}

type userInfoRepository struct {
	*Repository
	log *zap.Logger
}

func (r *userInfoRepository) Store(ctx context.Context, appid string, apikey []byte, cmk, smDefaultCmk string) error {
	m := model.UserInfo{
		Id:           model.UserinfoPartitionId(appid),
		Appid:        appid,
		ApiKey:       apikey,
		Cmk:          cmk,
		SmDefaultCmk: smDefaultCmk,
	}
	rev, err := r.db.Put(ctx, m.Id, m)
	if err != nil {
		return err
	}
	r.log.Info("create userinfo", zap.String("rev", rev), zap.Object("cmk", &m))
	return nil
}

func (r *userInfoRepository) GenHmac(ctx context.Context, appid string, data []byte) (string, error) {
	query := map[string]any{
		"selector": map[string]string{
			"_id": model.UserinfoPartitionId(appid),
		},
		"fields": []string{"appid", "apikey", "cmk"},
		"limit":  1,
	}

	rows, err := r.db.Find(ctx, query)
	if err != nil {
		return "", err
	}
	if !rows.Next() {
		return "", errors.New("appid failed")
	}

	m := model.UserInfo{}
	err = rows.ScanDoc(&m)
	if err != nil {
		return "", err
	}

	if len(m.ApiKey) == 0 {
		return "", errors.New("Unexpected Error")
	}
	signStr := base64.StdEncoding.EncodeToString(data)
	resp := new(ehsm.GenHmacResp)
	err = ehsm.GenHmacAction.Call(ehsm.GenHmacPayload{
		Cmk:     m.Cmk,
		ApiKey:  string(m.ApiKey),
		Payload: signStr,
	}, resp)
	if err != nil {
		return "", err
	}

	return resp.Result.Hmac, nil
}
